/* 手写类型判断函数(2) */
function fn1() {
    function getType(value) {
        // 判断数据是 nul1 的情况
        if (value === null) {
            return "null";
        }

        // 判断数据是引用类型的情况
        if (typeof value === "object") {
            /* 并非完美答案 */
            // let valueClass = Object.prototype.toString.call(value);
            // let type = valueClass.split(" ")[1].split("");
            // type.pop();
            // // console.log(value, value.toString(), valueClass, type);
            // return type.join("").toLowerCase();

            // 更好的答案
            // 主要是对象 直接拿到构造器的名字
            return value.constructor.name
        }

        // 判断数据是基本数据类型的情况和函数的情况
        return typeof value;
    }

    console.log(getType(null));//null
    console.log(getType("str"));//string
    console.log(getType({ type: "obj" }));//object
    console.log(getType(new Date()));//Date
    console.log(getType(/reg/));//RegExp

    class Person { }
    console.log(getType(new Person()));//Person
}

/* 使用Promise封装AJAX请求 */
function fn2() {
    /* 使用合并对象的方式做配置的合并 */
    function ajax(conf) {
        /* 使用合并对象的方式做默认配置 */

        // 默认配置
        const defaultConf = {
            method: "GET",
            onSuccess: (data) => console.log("data=", data),
            onFail: (err) => console.error("err=", err),

            // 将用户配置中的所有key-value打散 合并到defaultConf中
            ...conf,
        };

        let { method, url, data, dataType, onSuccess, onFail } = defaultConf;
        // console.log(method, url, data, dataType, onSuccess, onFail);

        /* 如果用户未传递URL 办它/弄死这只傻鸟 */
        if (!url) {
            // 弄死它的目的是为了引起其注意 以提前修正错误
            throw new Error("亲爱的傻鸟,URL必须传递哦~");
        }

        let body = null;

        const xhr = new XMLHttpRequest();

        xhr.onload = () => {
            onSuccess(xhr.responseText);
        };

        xhr.onerror = (err) => onFail(err);

        /* 为GET请求拼接查询参数字符串 */
        if (method === "GET" && data) {
            url += `?${getSearchParams(data)}`;
        }

        xhr.open(method, url);

        /* 设置Content-Type请求头（必须在xhr打开连接以后才能配置） */
        switch (true) {
            case dataType === "form":
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                body = getSearchParams(data);
                break;

            case dataType === "json":
                xhr.setRequestHeader("Content-Type", "application/json");
                body = JSON.stringify(data);
                break;

            default:
                break;
        }

        xhr.send(body);
    }

    /* 得到一个执行AJAX任务的Promise对象 */
    function ajaxPromise(conf) {
        /* 返回一个履约/毁约未可知的Promise对象 */
        return new Promise(
            // 执行网络请求
            (resolve, reject) => {
                ajax({

                    /* 重构成功与失败回调 */
                    // 成功时resolve数据
                    onSuccess: (data) => resolve(data),

                    // 失败时reject错误信息
                    onFail: (err) => reject(err),

                    // method,url,data,dataType...
                    ...conf,
                });
            }
        );

    }

    ajaxPromise({
        method: "POST",
        url: "http://httpbin.org/post",
        data: {
            name: "张三",
            nickname: "法外狂徒"
        },
        dataType: "json",
        onSuccess: data => console.log("data2=", data),
        onFail: err => console.log("err2=", err)
    })

}

/* 手写 Promise.then(2) */

/* 手写 call 函数(1) */
// fn.call(thisObj,...args)
function fn3() {
    Function.prototype.myCall = function (thisArg, ...args) {
        // console.log("this in myCall", this); //add
        thisArg.fn = this;

        const ret = thisArg.fn(...args);
        delete thisArg.fn;
        return ret;
    };

    function add(a, b) {
        console.log("add this=", this); //?
        return a + b;
    }

    const obj = { name: "张三" };
    console.log(add.myCall(obj, 2, 3)); //张三 5
    console.log(add.call(obj, 2, 3)); //张三 5
}

/* 将数字每千分位用逗号隔开(1) */
function fn4() {
    let format = n => {
        let num = n.toString()
        let len = num.length
        if (len <= 3) {
            return num
        } else {
            let remainder = len % 3
            if (remainder > 0) {
                // 不是3的整数倍
                return num.slice(0, remainder) + ',' + num.slice(remainder, len).match(/\d{3}/g).join(",")
            } else {
                // 是3的整数倍
                return num.slice(0, len).match(/\df3}/g).join(",")
            }
        }
    }

    console.log(format(1232323)); //1,232,323
}

/* 使用ES5和ES6求函数参数的和(1) */
function fn5() {
    function sum5() {
        let sum = 0
        Array.prototype.forEach.call(arguments, function (item) {
            sum += item
        })
        return sum
    }

    function sum6(...args) {
        let sum = 0
        args.forEach(item => sum += item)
        return sum
    }

    console.log(sum5(1, 2, 3, 4, 5));
    console.log(sum6(1, 2, 3, 4, 5));
}

/* 解析 URL Params 为对象(1) */
function fn6() {
    /**
     * 从url中提取查询参数 /add?a=2&b=3 => {a:2,b:3}
     * @param {string} url 用户请求的路径
     * @returns 提取好的查询参数形成的对象
     */
    function getSearchParams(url) {
        // 创建结果对象
        const obj = {};

        // 摘出a=2&b=3
        // "/add?a=123&b=456&c=789#abc".match(/\w+=\w+/g)
        // const reg = /?(.*)/;
        // const str = reg.exec(url)[1];
        // 使用&做分隔符 肢解字符串为[a=2,b=3]
        // const arr = str.split("&");

        // key=value
        // const reg = /\w+=\w+/g //key=value必须是单词字符
        const reg = /\w+=[^\s&=]+/g //value支持任意字符
        const arr = url.match(reg)//[子串1，子串2] [a=2,b=3]
        console.log("getSearchParams:arr=", arr);

        // 遍历上述数组 将每个元素以=肢解为 [a,2] 将这一组key-value收集到结果对象中
        arr.forEach((item) => {
            let [key, value] = item.split("=");
            obj[key] = value//obj.a = 2 obj.b=3
        });

        // 返回结果对象
        return obj;//{a:2,b:3}
    }

    console.log(getSearchParams("/add?a=2&b=3&c=张三"));
}

/* 全班学生成绩，过滤出及格学生成绩后，对前三名求平均值，并输出汉字成绩 */
function fn7() {
    const scores = [79, 56, 13, 90, 34, 66]
    const nums = "零一二三四五六七八九点"
    console.log(
        scores.filter(s => s > 59)
            .sort((a, b) => b - a)
            .slice(0, 3)
            .reduce((pv, cv) => pv + cv / 3, 0)//78.33
            .toString()
            .split("")
            .map(s => nums[!isNaN(Number(s)) ? s : 10])
            .join("")
    )
}

(function main() {
    // fn1()
    // fn2()
    // fn3()
    // fn4()
    // fn5()
    // fn6()
    // fn7()
})()